Skip to content

Comments

Enhance client support checks for MCP Apps UI rendering#2051

Merged
mattdholloway merged 11 commits intomainfrom
fix-mcp-apps-update-before-submit
Feb 24, 2026
Merged

Enhance client support checks for MCP Apps UI rendering#2051
mattdholloway merged 11 commits intomainfrom
fix-mcp-apps-update-before-submit

Conversation

@mattdholloway
Copy link
Contributor

@mattdholloway mattdholloway commented Feb 20, 2026

Summary

This pull request refactors how MCP Apps UI capability is detected and propagated throughout the server, switching from client name-based detection to standards-based extension detection, and adds context-based support for stateless servers. It also updates dependencies and third-party license documentation.

Why

Fixes #

What changed

Capability detection and context handling:

  • Refactored clientSupportsUI in pkg/github/ui_capability.go to detect MCP Apps UI support via the io.modelcontextprotocol/ui extension in client capabilities, falling back to context for stateless servers. Removed the workaround using client name matching.
  • Added WithUISupport and HasUISupport functions in pkg/context/request.go to store and retrieve MCP Apps UI support flags in context, enabling correct capability detection for stateless HTTP servers.
  • Updated all usages of clientSupportsUI in pkg/github/issues.go and pkg/github/pullrequests.go to accept context as a parameter, ensuring consistent capability detection. [1] [2]

Testing improvements:

  • Rewrote and expanded tests in pkg/github/ui_capability_test.go to cover detection via capability extensions and context, including precedence rules and nil cases.

MCP impact

  • No tool or API changes
  • Tool schema or behavior changed
  • New tool added

Prompts tested (tool changes only)

Security / limits

  • No security or limits impact
  • Auth / permissions considered
  • Data exposure, filtering, or token/size limits considered

Tool renaming

  • I am renaming tools as part of this PR (e.g. a part of a consolidation effort)
    • I have added the new tool aliases in deprecated_tool_aliases.go
  • I am not renaming tools as part of this PR

Note: if you're renaming tools, you must add the tool aliases. For more information on how to do so, please refer to the official docs.

Lint & tests

  • Linted locally with ./script/lint
  • Tested locally with ./script/test

Docs

  • Not needed
  • Updated (README / docs / examples)

@mattdholloway mattdholloway requested a review from a team as a code owner February 20, 2026 13:52
Copilot AI review requested due to automatic review settings February 20, 2026 13:52
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the MCP Apps UI capability detection so tools can decide whether to return an interactive-form flow even when the go-sdk session doesn’t reliably expose InitializeParams (notably in HTTP/stateless mode).

Changes:

  • Updated clientSupportsUI to accept a context.Context and fall back to a client name stored on the request context.
  • Added context helpers to store/retrieve MCP client name.
  • Updated call sites and expanded tests for the new detection behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/github/ui_capability.go Extends UI capability detection to check session first, then fall back to context-provided client name.
pkg/github/ui_capability_test.go Updates tests for new function signature and adds tests for context-based detection.
pkg/github/pullrequests.go Updates UI gating condition to pass ctx into clientSupportsUI.
pkg/github/issues.go Updates UI gating condition to pass ctx into clientSupportsUI.
pkg/context/request.go Adds WithClientName / GetClientName context helpers for propagating client identity in stateless flows.

Comment on lines 23 to 37
// It checks the go-sdk Session first (for stdio/stateful servers), then
// falls back to the request context (for HTTP/stateless servers where
// the session may not persist InitializeParams across requests).
func clientSupportsUI(ctx context.Context, req *mcp.CallToolRequest) bool {
// Try go-sdk session first (works for stdio/stateful servers)
if req != nil && req.Session != nil {
params := req.Session.InitializeParams()
if params != nil && params.ClientInfo != nil {
return uiSupportedClients[params.ClientInfo.Name]
}
}
params := req.Session.InitializeParams()
if params == nil || params.ClientInfo == nil {
return false
// Fall back to context (works for HTTP/stateless servers)
if name, ok := ghcontext.GetClientName(ctx); ok {
return uiSupportedClients[name]
}

This comment was marked as outdated.

Comment on lines 120 to 131
// WithClientName stores the MCP client name in the context.
// This is used by HTTP/stateless servers where req.Session may not have
// InitializeParams available on every request.
func WithClientName(ctx context.Context, name string) context.Context {
return context.WithValue(ctx, clientNameCtxKey{}, name)
}

// GetClientName retrieves the MCP client name from the context.
func GetClientName(ctx context.Context) (string, bool) {
name, ok := ctx.Value(clientNameCtxKey{}).(string)
return name, ok && name != ""
}

This comment was marked as outdated.

@mattdholloway mattdholloway self-assigned this Feb 20, 2026
@mattdholloway mattdholloway marked this pull request as draft February 20, 2026 14:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

pkg/github/ui_capability.go:22

  • The PR description mentions a new mechanism for passing/retrieving the client name via context, and has an unfinished Fixes # reference, but the implementation here stores a boolean WithUISupport/HasUISupport flag and does not reference client name. Please update the PR description (Summary/Why/What changed) to reflect the actual mechanism and link the intended issue, so reviewers and release notes match behavior.
// clientSupportsUI reports whether the MCP client that sent this request
// supports MCP Apps UI rendering.
// It checks the context first (set by HTTP/stateless servers from stored
// session capabilities), then falls back to the go-sdk Session (for stdio).
func clientSupportsUI(ctx context.Context, req *mcp.CallToolRequest) bool {
	// Check context first (works for HTTP/stateless servers)
	if supported, ok := ghcontext.HasUISupport(ctx); ok {
		return supported
	}

@mattdholloway mattdholloway force-pushed the fix-mcp-apps-update-before-submit branch from 1ee1767 to 4031c58 Compare February 20, 2026 15:09
Auto-generated by license-check workflow
@mattdholloway mattdholloway marked this pull request as ready for review February 20, 2026 15:26
@mattdholloway mattdholloway force-pushed the fix-mcp-apps-update-before-submit branch from a34d6cd to 36603de Compare February 20, 2026 15:39
Copy link

@arhiv1973b arhiv1973b left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! ✅

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 16 changed files in this pull request and generated 2 comments.

Comment on lines +16 to +19
// It checks the context first (set by HTTP/stateless servers from stored
// session capabilities), then falls back to the go-sdk Session (for stdio).
func clientSupportsUI(ctx context.Context, req *mcp.CallToolRequest) bool {
// Check context first (works for HTTP/stateless servers)
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clientSupportsUI now prefers a context flag for stateless/HTTP servers, but nothing in this repo currently sets that flag (the only WithUISupport usages are in tests). As a result, stateless HTTP requests will still fall back to the go-sdk session (which may not carry client capabilities across requests) and UI support may never be detected. Either wire WithUISupport into the HTTP request path (e.g., extract UI support from the initialize/capabilities for the request and set it on the request context), or adjust the comment/logic to reflect how this will actually be provided.

Suggested change
// It checks the context first (set by HTTP/stateless servers from stored
// session capabilities), then falls back to the go-sdk Session (for stdio).
func clientSupportsUI(ctx context.Context, req *mcp.CallToolRequest) bool {
// Check context first (works for HTTP/stateless servers)
// It first checks for a UI-support flag on the context (when explicitly set
// by the caller, e.g., HTTP/stateless servers that persist capabilities),
// then falls back to the go-sdk Session (for stdio/stateful servers).
func clientSupportsUI(ctx context.Context, req *mcp.CallToolRequest) bool {
// Prefer explicit context flag when provided (e.g., HTTP/stateless servers)

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a legit issue or not @mattdholloway? Will we only support this in remote and set the context on the request there, or should this also be supported in STDIO?

Comment on lines 309 to 315
caps := &mcp.ClientCapabilities{}
// If the client is a known UI-supporting client, add the UI extension
if clientName == "Visual Studio Code - Insiders" || clientName == "Visual Studio Code" {
caps.AddExtension("io.modelcontextprotocol/ui", map[string]any{
"mimeTypes": []string{"text/html;profile=mcp-app"},
})
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper now decides whether to add the UI extension by matching on clientName (VS Code names). Since UI support detection has been refactored away from client-name matching, consider making createMCPRequestWithSession accept an explicit *mcp.ClientCapabilities (or a uiSupported bool) so tests don’t implicitly rely on client-name heuristics and can set capabilities directly.

Copilot uses AI. Check for mistakes.

caps := &mcp.ClientCapabilities{}
// If the client is a known UI-supporting client, add the UI extension
if clientName == "Visual Studio Code - Insiders" || clientName == "Visual Studio Code" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to make these variables, rather than comparing strings?

If it's for tests only, do we want to explicitly say this test request supports UI? If it takes a ton of effort to change I'm not averse to it, but feels a little weird doing this here.

Comment on lines +16 to +19
// It checks the context first (set by HTTP/stateless servers from stored
// session capabilities), then falls back to the go-sdk Session (for stdio).
func clientSupportsUI(ctx context.Context, req *mcp.CallToolRequest) bool {
// Check context first (works for HTTP/stateless servers)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a legit issue or not @mattdholloway? Will we only support this in remote and set the context on the request there, or should this also be supported in STDIO?

@mattdholloway mattdholloway merged commit a94f95b into main Feb 24, 2026
16 checks passed
@mattdholloway mattdholloway deleted the fix-mcp-apps-update-before-submit branch February 24, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants